<template>
  <div class="signin-content">
    <div class="signin-title">{{ submitFormTitle }}</div>
    <div class="signin-type-tab" v-if="modalType === 'signin'">
      <ul>
        <li
          @click="signinType = 'account'"
          :class="{ active: signinType === 'account' }">密码登录</li>
        <li
          @click="signinType = 'email-code'"
          :class="{ active: signinType === 'email-code' }">验证码登录</li>
      </ul>
    </div>

    <el-form ref="signinFormRef" :model="loginForm" :rules="rules" label-position="top">
      <div v-if="modalType === 'signin'">
        <!-- gimimind账户登录 -->
        <div class="account-login-content login-content" v-if="signinType === 'account'">
          <div class="input-modal">
            <el-form-item prop="username">
              <el-input v-model="loginForm.username" placeholder="输入GminMind账号" size="large"></el-input>
            </el-form-item>
          </div>

          <div class="input-modal">
            <el-form-item prop="password">
              <el-input v-model="loginForm.password" placeholder="输入密码" autocomplete="new-password" type="password" show-password size="large"></el-input>
            </el-form-item>
          </div>

          <div class="input-modal">
            <el-form-item prop="captcha" class="captcha">
              <el-input v-model="loginForm.captcha" placeholder="输入验证码" size="large">
                <template #append>
                  <div v-html="captcha" @click="generateCaptcha" style="font-size: 0;"></div>
                </template>
              </el-input>
            </el-form-item>
          </div>
        </div>

        <!-- 邮箱验证码登录 -->
        <div class="email-code-login-content login-content" v-if="signinType === 'email-code'">
          <div class="input-modal">
            <el-form-item prop="email">
              <el-input v-model="loginForm.email" placeholder="输入Email邮箱" size="large"></el-input>
            </el-form-item>
          </div>
          <div class="input-modal">
            <el-form-item prop="emailCode">
              <el-input v-model="loginForm.emailCode" placeholder="输入验证码" size="large">
                <template #append>
                  <el-button type="primary" @click="sendEmailGetCode" :loading="sendEmailLoading">获取验证码</el-button>
                </template>
              </el-input>
            </el-form-item>
          </div>
        </div>
      </div>

      <!-- 账号注册 -->
      <div class="register-content login-content" v-if="modalType === 'register'">
        <div class="input-modal">
          <el-form-item prop="username">
            <el-input v-model="loginForm.username" placeholder="输入GminMind账号" size="large"></el-input>
          </el-form-item>
        </div>
        <div class="input-modal">
          <el-form-item prop="pass">
            <el-input v-model="loginForm.pass" placeholder="输入密码" autocomplete="new-password" type="password" show-password size="large"></el-input>
          </el-form-item>
        </div>
        <div class="input-modal">
          <el-form-item prop="confirmPass">
            <el-input v-model="loginForm.confirmPass" placeholder="再次输入密码" type="password" show-password size="large"></el-input>
          </el-form-item>
        </div>
        <div class="input-modal">
          <el-form-item prop="captcha" class="captcha">
            <el-input v-model="loginForm.captcha" placeholder="输入验证码" size="large">
              <template #append>
                <div v-html="captcha" @click="generateCaptcha" style="font-size: 0;"></div>
              </template>
            </el-input>
          </el-form-item>
        </div>
      </div>
    </el-form>

    <div class="login-button">
      <el-button type="primary" :loading="signinLoading" size="large" @click="handleSubmitSigninForm">{{ submitFormBtnText }}</el-button>
    </div>

    <div class="forget-password-tip" v-show="modalType === 'signin'" v-if="false">
      <p>忘记密码？</p>
    </div>

    <div class="create-account" v-if="modalType === 'signin'">
      <p @click="modalType = 'register'"><span>还没有创建账户？</span>创建账户</p>
    </div>

    <div class="has-account-gosignin" v-if="modalType === 'register'">
      <p @click="modalType = 'signin'">已有账号，去登录 <i class="ri-arrow-right-s-line"></i></p>
    </div>

    <div class="third-quick-login">
      <p class="tip">第三方快捷登录</p>
      <ul class="quick-type">
        <li>
          <a href="###">
            <i class="ri-wechat-fill"></i>
          </a>
        </li>
        <li>
          <a :href="`https://github.com/login/oauth/authorize?client_id=${GIT_CLIENT_ID}&redirect_uri=${GIT_REDIRECT_URL}&scope=user:email&state=${locationParams.redirect_url || ''}`">
            <i class="ri-github-fill"></i>
          </a>
        </li>
        <li>
          <a :href="`https://gitee.com/oauth/authorize?client_id=${GITEE_CLIENT_ID}&redirect_uri=${GITEE_REDIRECT_URL}&response_type=code&state=${locationParams.redirect_url || ''}`">
            <i class="iconfont icon-gitee1"></i>
          </a>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, onBeforeUnmount } from 'vue'
import { ElForm, ElMessage } from 'element-plus'
import { encrypt } from '@/utils/common'
import { userStore } from '@/store/user.store'
import { apiGetPublicKey, apiAccountLogin, apiSendEmailGetCode, apiEmailCodeLogin, apiRegisterUser, apiGetCaptcha } from '@/apis/auth'
import { GITEE_CLIENT_ID, GITEE_REDIRECT_URL, GIT_CLIENT_ID, GIT_REDIRECT_URL } from '@/config/oauth.config'
import { ruleRequired, RULE_EMAIL, RULE_NOSPACE, PASSWORD_RULE } from '@/utils/rules'
import type { LocationParams } from '@/types'

const signinFormRef = ref<null | InstanceType<typeof ElForm>>(null)
const loginForm = reactive({
  username: '',
  password: '',
  email: '',
  emailCode: '',
  pass: '',
  confirmPass: '',
  captcha: ''
})

const rules = {
  username: [ruleRequired(), RULE_NOSPACE],
  password: [ruleRequired(), RULE_NOSPACE,
    {
      validator: (_rule: any, value: any, callback: any) => {
        if (value.length < 6 || value.length > 20) {
          callback(new Error('密码长度要在-20位之间'))
        }
        callback()
      },
      trigger: 'blur'
    }
  ],
  email: [ruleRequired(), RULE_EMAIL],
  emailCode: [ruleRequired()],
  captcha: [ruleRequired()],
  pass: [ruleRequired(), PASSWORD_RULE, RULE_NOSPACE],
  confirmPass: [
    {
      validator: (_rule: any, value: any, callback: any) => {
        if (value !== loginForm.pass) {
          callback(new Error('两次输入的密码不一致'))
        }
        callback()
      },
      trigger: 'change'
    }
  ]
}

const signinType = ref<'account' | 'email-code'>('account')

const modalType = ref<'signin' | 'register'>('signin')

const locationParams = reactive<LocationParams>({})
/**
 * 获取url地址上的所有参数
 */
const getWindowLocationParams = async (): Promise<void> => {
  const searchParams = window.location.search.substring(1)
  const paramPairs = searchParams.split('&')

  paramPairs.forEach(pair => {
    if (pair) {
      const [key, value] = pair.split('=')
      locationParams[key] = decodeURIComponent(value || '')
    }
  })
}
getWindowLocationParams()

const captcha = ref('')
/**
 * 图片验证码获取
 */
const generateCaptcha = async () => {
  const data = await apiGetCaptcha()
  captcha.value = data
}
generateCaptcha()

const signinLoading = ref(false)
const handleSubmitSigninForm = async () => {
  if (modalType.value === 'signin') {
    let token = ''
    signinLoading.value = true
    try {
      if (signinType.value === 'account') {
        token = await handleAccountSignin()
      } else if (signinType.value === 'email-code') {
        token = await handleEmailCodeSignin()
      }
      window.localStorage.setItem('token', token)
      await userStore().queryUserProfile()
      ElMessage.success('登录成功')
      location.replace(locationParams.redirect_url || '/home')
    } finally {
      signinLoading.value = false
    }
  } else if (modalType.value === 'register') {
    handleRegisterAccount()
  }
}

/**
 * gimimind 账户名登录
 */
const handleAccountSignin = ():Promise<string> => {
  return new Promise((resolve, reject) => {
    signinFormRef.value?.validateField(['username', 'password', 'captcha'], async (valid) => {
      if (valid) {
        try {
          const publickey = await apiGetPublicKey()
          const password = encrypt(loginForm.password, publickey)
          const token = await apiAccountLogin({
            username: loginForm.username,
            password,
            captcha: loginForm.captcha
          })
          resolve(token)
        } catch (e) {
          generateCaptcha()
          reject(e)
        }
      }
      reject(valid)
    })
  })
}

/**
 * 邮箱验证码登录
 */
const handleEmailCodeSignin = ():Promise<string> => {
  return new Promise((resolve, reject) => {
    signinFormRef.value?.validateField(['email', 'emailCode'], async (valid) => {
      if (valid) {
        try {
          const token = await apiEmailCodeLogin(
            {
              email: loginForm.email,
              code: loginForm.emailCode
            }
          )
          resolve(token)
        } catch (e) {
          reject(e)
        }
      }
      reject(valid)
    })
  })
}

/**
 * gimimind 账户注册
 */
const handleRegisterAccount = async () => {
  signinFormRef.value?.validateField(['username', 'pass', 'confirmPass', 'captcha'], async (valid) => {
    if (valid) {
      signinLoading.value = true
      try {
        const publickey = await apiGetPublicKey()
        const password = encrypt(loginForm.pass, publickey)
        await apiRegisterUser(
          {
            username: loginForm.username,
            password,
            captcha: loginForm.captcha
          }
        )
        ElMessage.success('账号注册成功')
      } finally {
        signinLoading.value = false
        generateCaptcha()
      }
    }
  })
}

const sendEmailLoading = ref(false)
/**
 * 邮箱验证码发送
 */
const sendEmailGetCode = () => {
  signinFormRef.value?.validateField(['email'], async (valid) => {
    if (valid) {
      sendEmailLoading.value = true
      try {
        await apiSendEmailGetCode(loginForm.email)
        ElMessage.success('验证码发送成功')
      } finally {
        sendEmailLoading.value = false
      }
    }
  })
}

const submitFormBtnText = computed(() => {
  if (modalType.value === 'signin') {
    if (signinType.value === 'account') {
      return '登录'
    } else {
      return '登录/注册'
    }
  } else {
    return '注册'
  }
})

const submitFormTitle = computed(() => {
  if (modalType.value === 'signin') {
    return '登录 GimiMind 账户'
  } else {
    return '注册 GimiMind 账户'
  }
})

onMounted(() => {
  window.onkeydown = function (event) {
    if (event.code === 'Enter') {
      handleSubmitSigninForm()
    }
  }
})

onBeforeUnmount(() => {
  window.onkeydown = null
})
</script>

<style lang="scss" scoped>
.signin-content {
  width: 525px;
  margin: 0 auto;
  padding-top: 150px;
  height: calc(100vh - 162px);

  .signin-title {
    font-size: 25px;
    font-weight: 600;
    text-align: center;
    font-family: nevermind;
  }

  .signin-type-tab {
    margin: 32px 0 24px;
    ul {
      display: flex;
      justify-content: center;
      li {
        line-height: 1.5;
        padding: 8px 20px;
        border-radius: 6px;
        font-size: 15px;
        cursor: pointer;
        margin: 0 2px;
        user-select: none;
        &:hover {
          background-color: #eaecef;
        }
        &.active {
          background-color: #DFE1E5;
        }
      }
    }
  }

  .login-content {
    width: 366px;
    margin: 0 auto;

    &.register-content {
      margin-top: 42px;
    }

    .input-modal {
      margin-top: 18px;
      --el-component-size-large: 38px;
      --el-color-danger: #BF2A2A;

      :deep(.el-input) {

        &.el-input-group--append {
          .el-input__wrapper {
            border-radius: 6px 0 0 6px;
          }
        }

        .el-input__wrapper {
          border-radius: 6px;
          border: 1px solid #AEB5BD;
          box-shadow: none;

          .el-input__inner {
            font-size: 15px;
            font-family: nevermind;
            color: #000;
            line-height: 28px;
          }
        }

        .el-input-group__append {
          box-shadow: none;
          border: 1px solid #AEB5BD;
          border-left: none;
        }

        .el-input__icon {
          font-size: 18px;
          color: #000;
        }
      }

      :deep(.el-form-item) {

        &.is-error {

          .el-input__wrapper {
            border-color: #BF2A2A !important;
            box-shadow: inset 0 0 0 1px #BF2A2A !important;
          }
        }

        &.captcha {

          .el-input-group__append {
            padding: 0;
            overflow: hidden;
          }
        }

        .el-form-item__error {
          position: relative;
          padding-top: 6px;
          font-weight: 600;
        }

        .el-input-group__append {

          .el-button {
            display: flex;
            align-items: center;
          }
        }
      }
    }
  }

  .login-button {
    width: 366px;
    margin: 32px auto 24px;
    .el-button {
      display: flex;
      align-items: center;
      width: 100%;
      font-size: 15px;
      letter-spacing: 2px;
    }
  }

  .forget-password-tip, .create-account, .has-account-gosignin {
    text-align: center;

    p {
      cursor: pointer;
      display: inline-block;
      font-size: 12px;
      color: #111;
      line-height: 24px;

      &:hover {
        text-decoration: underline;
      }

      span {
        color: #999;
      }

      .ri-arrow-right-s-line {
        font-size: 13px;
      }
    }
  }

  .third-quick-login {
    width: 366px;
    margin: 20px auto 24px;
    position: relative;
    text-align: center;

    .tip {
      color: #999;
      display: inline-block;
      font-size: 13px;
      background-color: #fff;
      position: relative;
      z-index: 10;
      padding: 0 8px;
    }

    .quick-type {
      display: flex;
      justify-content: center;
      margin-top: 20px;

      li {
        border-radius: 50%;
        background-color: #DFE1E5;
        width: 36px;
        height: 36px;
        margin: 0 8px;

        a {
          color: #000;
          display: flex;
          width: 100%;
          height: 100%;
          align-items: center;
          justify-content: center;

          i {
            font-size: 22px;
          }
        }
      }
    }

    &:before {
      content: "";
      position: absolute;
      left: 0;
      right: 0;
      height: 1px;
      background-color: #0000000d;
      top: 12px;
    }
  }
}
</style>
